package com.jweight;

import java.util.ArrayList;
import java.util.HashMap;

import Jama.Matrix;

//import com.jWeight.JImage;

public class JweightAdjestAlgorithm {
	ArrayList<Matrix>constrainMatrix=new ArrayList<Matrix>();
	ArrayList<String>result=new ArrayList<String>();
	Matrix allInOne;
	private HashMap<String, Double> weightValMap=new HashMap<String, Double>();
	private ArrayList<String> basics=new ArrayList<String>();
	private int matrixSize;
	private ArrayList<String> topRow=new ArrayList<String>(); 
	private boolean doIteration=true;
	private boolean doNext=true;
	private boolean setWeigth=true;
	//private  HashMap<String, String> contextMap;
	private ArrayList<String>contextVariables;
	//private Probability proba;
	private int Imageindex=0;
	public JweightAdjestAlgorithm(ArrayList<String>contVariables,HashMap<String,Double > weightMap){
		//contextMap=conteMap;
		contextVariables=contVariables;
		weightValMap=weightMap;
	}
	
	// main method in the Algorithm which handle request
	public HashMap<String, Double> setWeightVal(String imgName,ArrayList<JImageComponent> elements ){
		
		for(int i=0;i<elements.size();i++){			
			if(elements.get(i).getImage().equals(imgName)){
				Imageindex=i;
			}		
		}
		if(Imageindex!=0){
			constrainMatrix=getConstrain(imgName, elements);		
			for(int i=0;i<constrainMatrix.size();i++){
				if(i==0){
					basics.add(0, "Z");				
				}else{
					basics.add("s"+i+"");
				}			
			}		
			for(int i=0;i<matrixSize;i++){
				if(i<contextVariables.size()){
					topRow.add(i,"x"+(i+1)+"");
				}else{
					topRow.add(i,"s"+ (i-2) +"");
				}			
			}		
			setRHSMatrix();	
			/*for(int i=0;i<constrainMatrix.size();i++){
				constrainMatrix.get(i).print(0, 3);
			}*/
			if((constrainMatrix.size()-1)!=3){
				while(doIteration){				
					firstIteration();
									
				}
			}			
			if(setWeigth){
				setResult(elements.get(Imageindex));
			}			
		}
		return weightValMap;
	}
	// this method get the result(new weight values) and print those value in a text file & return result.
	public void setResult(JImageComponent selectedImage){
		double newWeig=0,oldWeig=0,differ=0,totalProbability=0,change=0;
		HashMap<String, Double> differentValMap=new HashMap<String, Double>();
		ArrayList<Double>newWeigVal=new ArrayList<Double>();
		ArrayList<Double>oldWeigVal=new ArrayList<Double>();
		ArrayList<Double>differance=new ArrayList<Double>();		
		for(int i=0;i<contextVariables.size();i++){
			oldWeigVal.add(getWeightValueFromMap(contextVariables.get(i)));
			newWeigVal.add(0.0);
		}		
		for(int i=0;i<basics.size();i++){		
			for(int j=0;j<contextVariables.size();j++){
				if(basics.get(i).equals("x"+(j+1)+"")){
					newWeig= constrainMatrix.get(constrainMatrix.size()-1).get(0, i);
					try {
						newWeigVal.remove(j);
						newWeigVal.add(j,newWeig);
					} catch (Exception e) {
						// TODO: handle exception
					}														
				}					
			}			
		}
		for(int i=0;i<contextVariables.size();i++){
			totalProbability=totalProbability+selectedImage.getcontextProbabilityValueFromMap(contextVariables.get(i));
		}
		double avgTotalprobability=totalProbability/(contextVariables.size());
		System.out.println(avgTotalprobability);
		for(int x=0;x<oldWeigVal.size();x++){
			differ=(newWeigVal.get(x)-oldWeigVal.get(x));
			differentValMap.put(contextVariables.get(x), differ);
			differ=differ*avgTotalprobability;
			//System.out.print(differ);
			//System.out.print("        ");
			differance.add(differ);
			//System.out.println(differ);
			change =oldWeigVal.get(x)+differ;
			//System.out.println(change);
			setWeightValMap(contextVariables.get(x), change);
			//JFileWriter fw=new JFileWriter();
			//fw.createAllFiles("D1", "T1", "ST1", "51");
			
		}
		/*for(int i=0;i<differentValMap.size();i++){
			System.out.println(differentValMap.get(contextVariables.get(i)));
		}*/
		JFileWriter fw=new JFileWriter();
		fw.createAllFiles(differentValMap,avgTotalprobability);
		
	}
	//this method do the Iteration in simplex method
	public void firstIteration(){
		double [] minval;		
		double[]temp1=constrainMatrix.get(constrainMatrix.size()-1).getRowPackedCopy();
		double[]temp=constrainMatrix.get(constrainMatrix.size()-1).getRowPackedCopy();
		int pivotColumn=0,pivotRow=0,count=0;		
		String priCol="";		
		minval=getMinVal(temp);
		if(minval[0]<0){
			for(int i=0;i<minval.length;i++){
				if(minval[i]<0){
					for(int j=0;j<temp1.length;j++){				
						if(temp1[j]==minval[i]){
							pivotRow=j+1;					
							break;
						}
					}
					pivotColumn=getpivoteSORCol(pivotRow);					
					if(pivotColumn>=0){
						break;
					}				
				}else{
					break;
				}
			}
			pivotRow=getRatio(pivotColumn);
			if(pivotRow<0){
				
			}else{
				//System.out.println(priColum+" "+priRow);
				result.add(pivotColumn+""+pivotRow);	
				for(int i=0;i<result.size()-1;i++){
					for(int j=i+1;j<result.size();j++){
						if(result.get(i).equals(result.get(j))){
							count++;							
						}
					}					
				}
				if(doNext){
					divideByPivot(pivotColumn, pivotRow);				
					setRowVals(pivotColumn, pivotRow);
				}			
			}			
		}else{
			//System.out.println("now in else");
			pivotColumn=0;
			double [] objectRow1=constrainMatrix.get(0).getRowPackedCopy();
			double [] objectRow=constrainMatrix.get(0).getRowPackedCopy();
			minval=getMinVal(objectRow);
			if(minval[0]<0){
				for(int i=0;i<minval.length;i++){
					if(minval[i]<0){
						for(int j=0;j<objectRow1.length;j++){					
							if(objectRow1[j]==minval[i]){
								pivotColumn=j+1;					
								break;
							}
						}
						pivotRow=getRatio(pivotColumn);
						if(pivotRow>0){
							break;
						}						
					}
					else{
						break;
					}					
				}
				result.add(pivotColumn+""+pivotRow);
				for(int i=0;i<result.size()-1;i++){
					for(int j=i+1;j<result.size();j++){
						if(result.get(i).equals(result.get(j))){
							/*doIteration=false;
							doNext=false;*/
							count++;
						}
					}					
				}
				if(doNext){
					divideByPivot(pivotColumn, pivotRow);				
					setRowVals(pivotColumn, pivotRow);
				}
			}else{
				//doIteration=false;
				count++;
			}
		}			
		for(int i=0;i<result.size()-1;i++){
			for(int j=i+1;j<result.size();j++){
				if(result.get(i).equals(result.get(j))){
					//doIteration=false;
					count++;
				}
			}
		}
		if(pivotRow !=0){
			priCol=topRow.get(pivotColumn-1);
			try {
				basics.remove(pivotRow-1);
				basics.add(pivotRow-1, priCol);
			} catch (Exception e) {
				// TODO: handle exception
			}			
		}
		if(count>0){
			doIteration=false;
			doNext=false;
		}
	} 
	//This method used to divide pivot row from pivot element
	public void divideByPivot(int pivotColumn,int pivotRow){
		double priVal=0,rHSVal=0;		
		priVal=constrainMatrix.get(pivotRow-1).get(0, pivotColumn-1);		
		priVal=1/priVal;	
		constrainMatrix.get(pivotRow-1).timesEquals(priVal);
		rHSVal=constrainMatrix.get(constrainMatrix.size()-1).get(0, pivotRow-1);		
		rHSVal=rHSVal*priVal;
		try{
			constrainMatrix.get(constrainMatrix.size()-1).set(0,pivotRow-1 , rHSVal);
			for(int i=0;i<=matrixSize;i++){
			double allVal=allInOne.get(pivotRow-1, i)*priVal;
			allInOne.set(pivotRow-1, i, allVal);				
			}
		}catch (ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			e.getMessage();
		}		
	} 
	// This method used to do row operations in the matrix
	public void setRowVals(int pivotColumn, int pivotRow){
		double eleVal=0,rhsVal=0;		
		for(int i=0;i<constrainMatrix.size()-1;i++){
			
			if(i!=pivotRow-1 ){
				eleVal=constrainMatrix.get(i).get(0,pivotColumn-1);
				
				rhsVal=constrainMatrix.get(constrainMatrix.size()-1).get(0,pivotRow-1);
				
				rhsVal=(rhsVal*(- eleVal))+constrainMatrix.get(constrainMatrix.size()-1).get(0, i);
			
				constrainMatrix.get(i).plusEquals(constrainMatrix.get(pivotRow-1).times(-eleVal));
				
				constrainMatrix.get(constrainMatrix.size()-1).set(0, i,rhsVal);				
			}			
		}
	}
	// divide RHS column by pivot column and find the pivot row 
	public int getRatio(int pivotColumn){
		double [] tempval1=new double[constrainMatrix.size()-2];
		double firstval=0,secondval=0,min=0;;
		int loca=0,locaTemp=0;		
		for(int i=1;i<constrainMatrix.size()-1;i++){
			
			firstval=constrainMatrix.get(i).get(0, pivotColumn-1);			
			secondval=constrainMatrix.get(constrainMatrix.size()-1).get(0,i);
			
			if(firstval!=0){	
				tempval1[i-1]=secondval/firstval;
			}else if(firstval==0 || secondval==0){
				tempval1[i-1]=0;
			}
		}		
	
		for(int i=0;i<tempval1.length;i++){
			if(tempval1[i]>0){
				min=tempval1[i];
				loca=i;
				locaTemp=i;
				break;
			}			
		}
		if(min==0){
			doIteration=false;
			return -1;
		}
		if(min!=0){
			while(locaTemp<tempval1.length-1){
				if(tempval1[locaTemp+1]<0){
					min=tempval1[loca];
					locaTemp++;
				}else if(tempval1[locaTemp+1]>0 && min<tempval1[locaTemp+1]){
					min=tempval1[loca];
					locaTemp++;
				}else if(tempval1[locaTemp+1]>0 && min>tempval1[locaTemp+1]){
					min=tempval1[locaTemp+1];
					loca=locaTemp+1;
					locaTemp++;
				}
				locaTemp++;
			
			}
		}
		return loca+2;
	}
	// find the SOR column if there exit
	public int getpivoteSORCol(int location){
		double [] tempval1=new double[matrixSize];
		double [] tempval2=new double[matrixSize];
		double val1=0,min=0;
		int loca=0;
		
		Matrix A=constrainMatrix.get(location-1).arrayLeftDivide(constrainMatrix.get(0));
		tempval1=A.getRowPackedCopy();
		tempval2=A.getRowPackedCopy();
	
		for(int i=0;i<tempval1.length;i++){
			if(Math.abs(tempval1[i])>0 && Math.abs(tempval1[i])<1000){
				tempval1[i]=tempval1[i];
			}else{
				tempval1[i]=0;
			}
		} 
		int out, in;
	    for(out=tempval1.length-1; out>1; out--){ // outer loop (backward)
	          for(in=0; in<out; in++){ // inner loop (forward)
	        	  if( Math.abs(tempval1[in]) > Math.abs(tempval1[in+1]) ){ // out of order?
	        		 double temp = tempval1[in];
	        		  tempval1[in] = tempval1[in+1];
	        		  tempval1[in+1] = temp;
	        	  }	        	  
	          }          
	    }	  
		for(int i=0;i<tempval1.length;i++){			
			val1=tempval1[i];
			if(val1!=0){
				min=val1;
				break;
			}
		}		
		for(int i=0;i<tempval2.length;i++){
			if(tempval2[i]==min){
				loca=i+1;
			}else if(min==0){
				return -1;
			}
		}
		
		return loca;		
	}	
	public double [] getMinVal(double [] temp){
		for (int i = 1; i < temp.length; i++){
		      int j = i;
		      double B = temp[i];
		      while ((j > 0) && (temp[j-1] > B)){
		    	  temp[j] = temp[j-1];
		        j--;
		      }
		      temp[j] = B;		      
		      
		}	
		return temp;
	}
	// get RHS matrix
	public void setRHSMatrix() {
		
		int x=constrainMatrix.size();
		double [] sDiffer=new double[x];
		for(int i=0;i<x-1;i++){
			sDiffer[i]=0;
		}
		sDiffer[x-2]=100;
		sDiffer[x-1]=-100;
		Matrix rHs=new Matrix(sDiffer,1);		
		constrainMatrix.add(rHs);
		try{			
			for(int i=0;i<sDiffer.length;i++){
				allInOne.set(i,8,sDiffer[i]);
			}		
		}catch(ArrayIndexOutOfBoundsException ex){
			ex.getMessage();
		}		
	}
	// get all the constrain and put them in a matrix
	public ArrayList<Matrix> getConstrain(String imgName,ArrayList<JImageComponent> elements ){		
		
		ArrayList<Matrix>constMatrix=new ArrayList<Matrix>();
		int noContext=contextVariables.size();	
		double  [] fDiffer=null;
		int index=0,number=0,count=0,check=0,checkEqal=0;
		int removeVal=0;
		double value;
		matrixSize=(2*(elements.size())+2);
		//get the index of the selected image
		
		for(int i=0;i<elements.size();i++){			
			if(elements.get(i).getImage().equals(imgName)){
				index=i;
			}		
		}
		//get the constrain by using pro values			
		for(int i=0;i<elements.size();i++){			
			if(i!=index){
				for(int x=0;x<noContext;x++){
					value=elements.get(i).getcontextProbabilityValueFromMap(contextVariables.get(x))-elements.get(index).getcontextProbabilityValueFromMap(contextVariables.get(x));
					if(value>=0){
						number++;			
					}
				}				
				if(noContext==number ){
					check=i;					
					//matrixSize=matrixSize-(i+2-check);
					removeVal++;					
				}
				number=0;				
			}
			
		}
		if(check<index){
			matrixSize=matrixSize-(check+1);
		}else if(check>index){
			matrixSize=matrixSize-(check+2);
		}
		if(removeVal==elements.size()-1){
			System.out.println("pissekda oi");
			doIteration=false;
			setWeigth=false;
		}
		for(int i=0;i<elements.size()-1;i++){			
			if(i==index){
				i++;				
			}
			int j=i+1;
			if(j==index){
				j++;						
			}
			if(j>=(elements.size())){
				break;
			}
			fDiffer=new double [matrixSize];
			for(int x=0;x<noContext;x++){
				value=elements.get(j).getcontextProbabilityValueFromMap(contextVariables.get(x))-elements.get(i).getcontextProbabilityValueFromMap(contextVariables.get(x));
				fDiffer[x]=value;
			}			
				//get the identity part of the matrix
				for(int x=noContext;x<fDiffer.length;x++){
					if(i<index){
						if(x==i+noContext){
							fDiffer[noContext+i]=1.0;
						}else{
							fDiffer[x]=0;
						}			
					}else{
						if(x==i+3){
							fDiffer[noContext+i-1]=1.0;
						}else{
							fDiffer[x]=0;
						}
					}					
				}
				try{
					Matrix A=new Matrix(fDiffer,1);
					constMatrix.add(A);										
				
				}catch(IllegalArgumentException ex){
					ex.getMessage();
				}catch(ArrayIndexOutOfBoundsException ex){
					ex.getMessage();
				}							
		}
		//System.out.println(elements.size());
		for(int i=0;i<elements.size();i++){			
			if(i!=index){
				for(int x=0;x<noContext;x++){
					value=elements.get(i).getcontextProbabilityValueFromMap(contextVariables.get(x))-elements.get(index).getcontextProbabilityValueFromMap(contextVariables.get(x));
					if(value>=0){
						number++;
					}
				}
				if(number==noContext){
					check=i;
				}
				number=0;				
			}
		}
		for(int i=0;i<check+1;i++){
			try {
				if(index==0) {
					elements.remove(1);	
				}else if(index!=0) {
					elements.remove(0);												
					index--;
					Imageindex--;
				}else{
					break;
				}
			} catch (Exception e) {
				// TODO: handle exception
			}
		}	
		
		for(int i=0;i<elements.size();i++){				
			if(i!=index){				
				fDiffer=new double [matrixSize];
				for(int x=0;x<noContext;x++){
					value=elements.get(i).getcontextProbabilityValueFromMap(contextVariables.get(x))-elements.get(index).getcontextProbabilityValueFromMap(contextVariables.get(x));
					fDiffer[x]=value;
				}				
				//get the identity part of the matrix
				for(int j=noContext;j<fDiffer.length;j++){
					if(i<index){
						if(j==noContext+constMatrix.size()){
							fDiffer[j]=1.0;
						}else{
							fDiffer[j]=0;							
						}					
					}else{
						if(j==noContext+constMatrix.size()-1){
							fDiffer[j]=1.0;
						}else{
							fDiffer[j]=0;							
						}	
					}				
				}
				try{
					Matrix A=new Matrix(fDiffer,1);
					constMatrix.add(A);				
					
				}catch(IllegalArgumentException ex){
					ex.getMessage();
				}catch(ArrayIndexOutOfBoundsException ex){
					ex.getMessage();
				}								
			}
			//Make objective row in the matrix
			else {
				fDiffer=new double [matrixSize];
				for(int x=0;x<noContext;x++){
					value=-elements.get(index).getcontextProbabilityValueFromMap(contextVariables.get(x));
					fDiffer[x]=value;
				}				
				for(int j=noContext;j<fDiffer.length;j++){
					fDiffer[j]=0;
				}
				try{
					Matrix A=new Matrix(fDiffer,1);				
					constMatrix.add(0, A);					
				}catch(IllegalArgumentException ex){
					ex.getMessage();
				}										
			}			
		}
		fDiffer[0]=1.0;fDiffer[1]=1.0;fDiffer[2]=1.0;
		
		for(int i=3;i<fDiffer.length;i++){			
			if(i!=fDiffer.length-2){				
				fDiffer[i]=0;
			}else{
				fDiffer[fDiffer.length-2]=1.0;
			}			
		}
		try{
			Matrix A=new Matrix(fDiffer,1);
			constMatrix.add(A);			
		}catch(IllegalArgumentException ex){
			ex.getMessage();
		}		
		fDiffer[0]=-1.0;fDiffer[1]=-1.0;fDiffer[2]=-1.0;
		
		for(int i=3;i<fDiffer.length;i++){
			if(i!=fDiffer.length-1){				
				fDiffer[i]=0;
			}else{
				fDiffer[fDiffer.length-1]=1.0;
			}				
		}
		try{
			Matrix B=new Matrix(fDiffer,1);
			constMatrix.add(B);			
		}catch(IllegalArgumentException ex){
			ex.getMessage();
		}
		// get all in a one Matrix 
		allInOne=new Matrix(constMatrix.size(),matrixSize+1);		
		try{
			for(int i=0;i<constMatrix.size();i++){				
				allInOne.setMatrix(i,i,0,matrixSize-1,constMatrix.get(i));				
				
			}
		}catch(ArrayIndexOutOfBoundsException ex){
				ex.getMessage();
		}		
		return constMatrix;		
	}
	public void setWeightValMap(String contextVariable,Double weightValue)
	{
		weightValMap.put(contextVariable, weightValue);
		
	}
	public Double getWeightValueFromMap(String contextVarible)
	{
		return weightValMap.get(contextVarible);
	}

}

